package com.goldenriver.fataar

import com.android.build.gradle.api.LibraryVariant
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.ProjectConfigurationException
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.artifacts.ResolvedDependency

/**
 * plugin entry
 */
class FatAarPlugin implements Plugin<Project> {

    public static final String ARTIFACT_TYPE_AAR = 'aar'

    public static final String ARTIFACT_TYPE_JAR = 'jar'

    private static final String CONFIG_NAME = "embed"

    public static final String CONFIG_SUFFIX = 'Embed'

    private Project project

    private RClassesTransform transform

    private final Collection<Configuration> embedConfigurations = new ArrayList<>()

    @Override
    void apply(Project project) {
        println("hahahah ===================================,we begin")
        this.project = project
        checkAndroidPlugin()
        FatUtils.attach(project)
        DirectoryManager.attach(project)
        project.extensions.create(FatAarExtension.NAME, FatAarExtension)
        createConfigurations()
        registerTransform()
        project.afterEvaluate {
            doAfterEvaluate()
        }
    }

    private registerTransform() {
        transform = new RClassesTransform(project)
        // register in project.afterEvaluate is invalid.
        project.android.registerTransform(transform)
    }

    private void doAfterEvaluate() {
        println("hahahah ===================================start foreach")
        embedConfigurations.each {
            println("configuration.name:${it.name }")
            if (project.fataar.transitive) {
                it.transitive = true
            }
        }
        println("hahahah ===================================end foreach")

        Collection<String> added = new ArrayList<>()

        project.android.libraryVariants.all { variant ->
            println("hahahah +++++++++++++++++++++++++++++++++++++++++++++++++++++start libraryVariants:${variant.getFlavorName()}")
            Collection<ResolvedArtifact> artifacts = new ArrayList()
            Collection<ResolvedDependency> firstLevelDependencies = new ArrayList<>()
            embedConfigurations.each { configuration ->
                println("================start embedConfigurations configuration.name :${configuration.name}")
                if (configuration.name == CONFIG_NAME
                        || configuration.name == variant.getBuildType().name + CONFIG_SUFFIX
                        || configuration.name == variant.getFlavorName() + CONFIG_SUFFIX
                        || configuration.name == variant.name + CONFIG_SUFFIX) {

//                    if (!added.contains(configuration.name)) {
//                        added.add(configuration.name)
//                        println("add configuration.name     :${configuration.name }")
//                        println("add variant.getFlavorName():${variant.getFlavorName()}")
//
//                        Collection<ResolvedArtifact> resolvedArtifacts = resolveArtifacts(configuration)
//                        artifacts.addAll(resolvedArtifacts)
//                        artifacts.addAll(dealUnResolveArtifacts(configuration, variant as LibraryVariant, resolvedArtifacts))
//                        firstLevelDependencies.addAll(configuration.resolvedConfiguration.firstLevelModuleDependencies)
//                    }
                    added.add(configuration.name)
                    println("add configuration.name     :${configuration.name }")
                    println("add variant.getFlavorName():${variant.getFlavorName()}")

                    Collection<ResolvedArtifact> resolvedArtifacts = resolveArtifacts(configuration)
                    artifacts.addAll(resolvedArtifacts)
                    artifacts.addAll(dealUnResolveArtifacts(configuration, variant as LibraryVariant, resolvedArtifacts))
                    firstLevelDependencies.addAll(configuration.resolvedConfiguration.firstLevelModuleDependencies)
                }
                println("================end  embedConfigurations configuration.name :${configuration.name} end")
            }

            if (!artifacts.isEmpty()) {
                def processor = new VariantProcessor(project, variant)
                processor.processVariant(artifacts, firstLevelDependencies, transform)
            }
            println("hahahah +++++++++++++++++++++++++++++++++++++++++++++++++++++ end  libraryVariants:${variant.getFlavorName()} end")
        }
    }

    private void createConfigurations() {
        Configuration embedConf = project.configurations.create(CONFIG_NAME)
        createConfiguration(embedConf)
        FatUtils.logInfo("Creating configuration embed")

        project.android.buildTypes.all { buildType ->
            String configName = buildType.name + CONFIG_SUFFIX
            Configuration configuration = project.configurations.create(configName)
            createConfiguration(configuration)
            FatUtils.logInfo("Creating configuration " + configName)
        }

        Collection<String> configured = new ArrayList<>()
        Collection<String> mixed = new ArrayList<>()
        println("hahahah ===================================flavorDimensions: ${project.android.flavorDimensions}")
        println("hahahah ===================================project.android: ${project.android}")


        // Do flavor, not consider their dimension
        project.android.productFlavors.all { flavor ->
            // Add flavorEmbed
            String configName = flavor.name + CONFIG_SUFFIX
            Configuration configuration = project.configurations.create(configName)
            createConfiguration(configuration)


            println("hahahah ===================================productFlavors flavor name: ${flavor.name}")

            // Add for example: flavorDebugEmbed
            project.android.buildTypes.all { buildType ->
                String variantName = flavor.name + buildType.name.capitalize()
                String variantConfigName = variantName + CONFIG_SUFFIX
                Configuration variantConfiguration = project.configurations.create(variantConfigName)
                createConfiguration(variantConfiguration)
//                configured.add(variantConfigName)
            }

            // todo: We want flavor1Flavor2Embed config. This way is ugly but just work.
            String currentName = flavor.name
            if (configured.size() == 0) {
                configured.add(currentName)
            } else {
                for (int i = 0; i < configured.size(); i++) {
                    addMixedConfig(configured[i], currentName)
                    addMixedConfig(currentName, configured[i])
//                    configured.add(currentName)

//                    String flavorName = configured[i] + currentName.capitalize()
//                    String flavorConfigName = flavorName + CONFIG_SUFFIX
//                    Configuration flavorConfiguration = project.configurations.create(flavorConfigName)
//                    createConfiguration(flavorConfiguration)
//                    println("hahahah ===================================bad add : ${flavorConfigName}")
//                    project.android.buildTypes.all { buildType ->
//                        String variantName = flavorName + buildType.name.capitalize()
//                        String variantConfigName = variantName + CONFIG_SUFFIX
//                        Configuration variantConfiguration = project.configurations.create(variantConfigName)
//                        createConfiguration(variantConfiguration)
//                        println("hahahah ===================================bad add 2 : ${variantConfigName}")
//                    }
                }
                configured.add(currentName)
            }
        }

        println("hahahah ===================================configured.size(): ${configured.size()}")
        // todo: Now we only can support 2 dimensions in this way, not good!!!!!!
//        for (int i = 0; i < configured.size(); i++) {
//            for (int j = 0; j < configured.size(); j++) {
//                if (i == j) {
//                    continue
//                }
//                String flavorName = configured[i] + configured[j].capitalize()
//                String configName = flavorName + CONFIG_SUFFIX
//                Configuration configuration = project.configurations.create(configName)
//                createConfiguration(configuration)
//                println("hahahah ===================================bad add : ${configName}")
//                project.android.buildTypes.all { buildType ->
//                    String type = buildType.name.capitalize()
//                    String variantName = flavorName + type
//                    String variantConfigName = variantName + CONFIG_SUFFIX
//                    Configuration variantConfiguration = project.configurations.create(variantConfigName)
//                    createConfiguration(variantConfiguration)
//                    println("hahahah ===================================bad add variantConfigName : ${variantConfigName}")
////                configured.add(variantConfigName)
//                }
//            }
//        }



//        String configName1 = "engDev" + CONFIG_SUFFIX
//            println("hahahah ===================================add in createConfigurations:$configName1")
//            Configuration configuration11 = project.configurations.create(configName1)
//            createConfiguration(configuration11)


//                    String configName1 = "engDev" + CONFIG_SUFFIX
//            println("hahahah ===================================add in createConfigurations:$configName1")
//            Configuration configuration11 = project.configurations.create(configName1)
//            createConfiguration(configuration11)






        println("hahahah ===================================project.android.libraryVariants loop: ${project.android.libraryVariants}")




        // Do flavor with dimension
        project.android.libraryVariants.all { variant ->
            // This is flavor1Flavor2
            println("hahahah ===================================libraryVariants loop: ${variant.getFlavorName()}")
//            String configName = "engDev" + CONFIG_SUFFIX
//            if (!configured.contains(configName)) {
//                println("hahahah ===================================add $configName")
//                configured.add(configName)
//                Configuration configuration = project.configurations.create(configName)
//                createConfiguration(configuration)
//            }

            String configName = variant.getFlavorName() + CONFIG_SUFFIX
            if (!configured.contains(configName)) {
//                println("hahahah ===================================add $configName")
//                configured.add(configName)
//                Configuration configuration = project.configurations.create(configName)
//                createConfiguration(configuration)
            }

            project.android.buildTypes.all { buildType ->
                // This is flavor1Flavor2Debug
                String variantName = variant.getFlavorName() + buildType.name.capitalize()
                String variantConfigName = variantName + CONFIG_SUFFIX
                if (!configured.contains(variantConfigName)) {
//                    println("hahahah ===================================add2 $variantConfigName")
//                    configured.add(variantConfigName)
//                    Configuration configuration = project.configurations.create(variantConfigName)
//                    createConfiguration(configuration)
                }
            }
        }
        println("hahahah ===================================createConfiguration end")
    }

    private void addMixedConfig(String flavor1, String flavor2) {
        String mixedName = flavor1 + flavor2.capitalize()
        String configName = mixedName + CONFIG_SUFFIX
        Configuration configuration = project.configurations.create(configName)
        createConfiguration(configuration)
        // Add for example: flavor1Flavor2DebugEmbed
        project.android.buildTypes.all { buildType ->
            String variantName = mixedName + buildType.name.capitalize()
            String variantConfigName = variantName + CONFIG_SUFFIX
            Configuration variantConfiguration = project.configurations.create(variantConfigName)
            createConfiguration(variantConfiguration)
        }
    }

    private void checkAndroidPlugin() {
        if (!project.plugins.hasPlugin('com.android.library')) {
            throw new ProjectConfigurationException('fat-aar-plugin must be applied in project that' +
                    ' has android library plugin!', null)
        }
    }

    private void createConfiguration(Configuration embedConf) {
        embedConf.visible = false
        embedConf.transitive = false
        project.gradle.addListener(new EmbedResolutionListener(project, embedConf))
        embedConfigurations.add(embedConf)
    }

    private Collection<ResolvedArtifact> resolveArtifacts(Configuration configuration) {
        def set = new ArrayList()
        if (configuration != null) {
            configuration.resolvedConfiguration.resolvedArtifacts.each { artifact ->
                if (ARTIFACT_TYPE_AAR == artifact.type || ARTIFACT_TYPE_JAR == artifact.type) {
                    //
                } else {
                    throw new ProjectConfigurationException('Only support embed aar and jar dependencies!', null)
                }
                set.add(artifact)
            }
        }
        return set
    }

    private Collection<ResolvedArtifact> dealUnResolveArtifacts(Configuration configuration, LibraryVariant variant, Collection<ResolvedArtifact> artifacts) {
        def artifactList = new ArrayList()
        configuration.resolvedConfiguration.firstLevelModuleDependencies.each { dependency ->
            def match = artifacts.any { artifact ->
                dependency.moduleName == artifact.moduleVersion.id.name
            }

            if (!match) {
                def flavorArtifact = FlavorArtifact.createFlavorArtifact(project, variant, dependency)
                if (flavorArtifact != null) {
                    artifactList.add(flavorArtifact)
                }
            }
        }
        return artifactList
    }
}
